package com.sdy.usercenter.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.MapUtil;
import com.sdy.usercenter.biz.mapper.SysRoleResourceMapper;
import com.sdy.usercenter.biz.model.SysResource;
import com.sdy.usercenter.biz.mapper.SysResourceMapper;
import com.sdy.usercenter.biz.model.SysRoleResource;
import com.sdy.usercenter.biz.service.SysResourceService;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统资源表 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2019-06-14
 */
@Slf4j
@Service
public class SysResourceServiceImpl extends BaseServiceImpl<SysResource> implements SysResourceService {
    @Autowired
    private SysResourceMapper sysResourceMapper;
    @Autowired
    private SysRoleResourceMapper sysRoleResourceMapper;

    @Override
    public List<SysResource> findResourceWithAuthByRoleId(Integer roleId) {
        return sysResourceMapper.findResourceWithAuthByRoleId(roleId);
    }

    @Override
    public SysResource appTreeDataWithAuth(String appCode, Integer roleId) throws BizException {
        SysResource appTree = this.appTreeData(appCode, true);
        List<SysRoleResource> roleResList = sysRoleResourceMapper.selectList(new LambdaQueryWrapper<SysRoleResource>()
                .eq(SysRoleResource::getRoleId, roleId)
                .eq(SysRoleResource::getRootResourceId, appTree.getId()));
        Map<Integer, SysRoleResource> authMap = MapUtil.collectionToMap(roleResList, SysRoleResource::getResourceId);
        MapUtil.traverseTree(appTree, SysResource::getChildren, item -> {
            item.setAuthed(authMap.containsKey(item.getId()));
            if (item.getAuthed()) {
                Integer sort = authMap.get(item.getId()).getSort();
                item.setSort(sort == null ? 0x7FFFFFFF : sort);
            }
            return item;
        });
        this.sortChildren(appTree);
        return appTree;
    }

    /**
     * 权限排序，主要是菜单排序
     */
    private void sortChildren(SysResource parentNode) {
        if (parentNode.getChildren() != null && !parentNode.getChildren().isEmpty()) {
            parentNode.getChildren().sort((o1, o2) -> {
                if (o1.getAuthed() && o2.getAuthed() && !o1.getSort().equals(o2.getSort())) {
                    return o1.getSort() - o2.getSort();
                } else {
                    return o1.getId() - o2.getId();
                }
            });
            parentNode.getChildren().forEach(this::sortChildren);
        }
    }

    @Override
    public SysResource appTreeData(String appCode, Boolean validOnly) throws BizException {
        SysResource root = lambdaQuery().eq(SysResource::getCode, appCode).one();
        Assert.isNull(root, "应用数据错误！");
        root.setChildren(new ArrayList<>());
        List<SysResource> resList = lambdaQuery()
                .eq(SysResource::getRootId, root.getId())
                .eq(validOnly, SysResource::getState, 1)
                .orderByAsc(SysResource::getId)
                .list();
        Map<Integer, List<SysResource>> pMap = new HashMap<>();
        resList.forEach(res -> {
            List<SysResource> arr = pMap.computeIfAbsent(res.getParentId(), key -> new ArrayList<>());
            arr.add(res);
        });
        resList.forEach(res -> {
            res.setChildren(pMap.get(res.getId()));
            if (res.getParentId().equals(root.getId())) {
                root.getChildren().add(res);
            }
        });
        return root;
    }

    @Override
    public void createResource(SysResource resource) throws BizException {
        resource.setState(1);
        resource.setCreateTime(new Date());
        if (!resource.getType().equals(2)) {
            resource.setRoute("");
        }
        if (resource.getParentId() == null) {
            resource.setParentId(0);
        } else {
            SysResource parent = this.getById(resource.getParentId());
            if (parent != null) {
                resource.setRootId(parent.getRootId());
            }
        }
        Assert.isTrue(lambdaQuery()
                        .eq(SysResource::getCode, resource.getCode())
                        .eq(SysResource::getRootId, resource.getRootId())
                        .count() > 0, 
                "权限编码重复");
        this.save(resource);
    }

    @Override
    public void updateResource(SysResource resource) throws BizException {
        SysResource r = getById(resource.getId());
        Assert.isTrue(lambdaQuery()
                        .eq(SysResource::getCode, resource.getCode())
                        .eq(SysResource::getRootId, r.getRootId())
                        .ne(SysResource::getId, r.getId())
                        .count() > 0,
                "权限编码重复");
        if (!resource.getType().equals(2)) {
            resource.setRoute("");
        }
        updateById(new SysResource()
                .setId(resource.getId())
                .setCode(resource.getCode())
                .setType(resource.getType())
                .setUrl(resource.getUrl())
                .setRoute(resource.getRoute())
                .setAuthorization(resource.getAuthorization())
                .setAuthentication(resource.getAuthentication())
                .setName(resource.getName()));
    }

    @Override
    public void deleteResource(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }
        Set<Integer> toRmIdList = new HashSet<>(ids);
        Set<Integer> parentIdList = new HashSet<>(ids);
        int t = 50;
        while (t-- > 0) {
            List<Integer> childrenIdList = lambdaQuery()
                    .select(SysResource::getId)
                    .in(SysResource::getParentId, parentIdList)
                    .list().stream().map(SysResource::getId).collect(Collectors.toList());
            if (childrenIdList.isEmpty()) {
                break;
            }
            parentIdList.clear();
            parentIdList.addAll(childrenIdList);
            toRmIdList.addAll(childrenIdList);
        }
        removeByIds(toRmIdList);
        // 删除已分配的权限
        sysRoleResourceMapper.delete(new LambdaQueryWrapper<SysRoleResource>().in(SysRoleResource::getResourceId, toRmIdList));
    }
}
